package com.tianji.learning.utils;

import cn.hutool.json.JSONUtil;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.JsonUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.learning.entity.LearningLesson;
import com.tianji.learning.entity.LearningRecord;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.DelayQueue;

@Slf4j
@Component
@RequiredArgsConstructor
public class LearningRecordDelayTaskHandler {

    private final StringRedisTemplate redisTemplate;
    private final LearningRecordMapper recordMapper;
    private final ILearningLessonService lessonService;
    private final DelayQueue<DelayTask<RecordTaskData>> queue = new DelayQueue<>();
    private final static String RECORD_KEY_TEMPLATE = "learning:record:{}";
    private static volatile boolean begin = true;

    @PostConstruct
    public void init(){
        log.info("延迟队列开始异步执行!");
        CompletableFuture.runAsync(this::handleDelayTask);
    }
    @PreDestroy
    public void destroy(){
        begin = false;
        log.debug("延迟任务停止执行！");
    }


    /**
     * 消费延时队列消息
     */
    public void handleDelayTask(){
        while (begin){
            log.info("正在等待延迟队列任务");
            try{
                RecordTaskData data = queue.take().getData();
                //1.获取redis缓存中的数据
                LearningRecord learningRecord = this.readRecordCache(data.getLessonId(), data.getRecordId());
                log.info("获取到redis中的缓存记录：{}",learningRecord);
                if (learningRecord == null) {
                    continue;
                }
                //2.拿队列中数据与redis中比较  否？跳过：需要记录数据库
                if(!data.getMoment().equals(learningRecord.getMoment())){
                    log.info("视频正在播放：播放时长{}",data.getMoment());
                    continue;
                }
                //3.记录数据库当前时长
                log.info("视频已退出播放：播放时长{}",learningRecord.getMoment());
                learningRecord.setUpdateTime(LocalDateTime.now());
                //避免状态改变
                learningRecord.setFinished(null);
                this.recordMapper.updateById(learningRecord);
                //4.更新课表的最近学习记录和时间
                LearningLesson lesson = LearningLesson.builder().id(data.getLessonId())
                        .latestLearnTime(LocalDateTime.now())
                        .latestSectionId(learningRecord.getSectionId())
                        .build();
                this.lessonService.updateById(lesson);
            }catch (Exception e){
                log.debug("消费延迟队列中任务时出问题了");
            }
            
        }
    }

    public void addLearningRecordTask(LearningRecord record){
        // 1.添加数据到Redis缓存
        writeRecordCache(record);
        // 2.提交延迟任务到延迟队列 DelayQueue
        queue.add(new DelayTask<>(new RecordTaskData(record), Duration.ofSeconds(8)));
    }

    public void writeRecordCache(LearningRecord record) {
        log.debug("更新学习记录的缓存数据");
        try {
            //组装大key
            String key = StringUtils.format(RECORD_KEY_TEMPLATE,record.getLessonId());
            //缓存数据
            RecordCacheData data = new RecordCacheData(record);
            String json = JSONUtil.toJsonStr(data);
            //直接put
            this.redisTemplate.opsForHash().put(key,record.getSectionId().toString(),json);
            
            redisTemplate.expire(key, Duration.ofMinutes(10));
        } catch (Exception e) {
            log.error("更新学习记录缓存异常", e);
        }
    }

    public LearningRecord readRecordCache(Long lessonId, Long id){
        try {
            // 1.读取Redis数据
            String key = StringUtils.format(RECORD_KEY_TEMPLATE,lessonId.toString());
            Object catchData = this.redisTemplate.opsForHash().get(key, id.toString());
            // 2.数据检查和转换
            if (catchData == null) {
                return null;
            }else {
                RecordCacheData cacheData = (RecordCacheData)catchData;
                return LearningRecord.builder().sectionId(cacheData.getId())
                        .moment(cacheData.getMoment())
                        .finished(cacheData.getFinished())
                        .build();
            }
        } catch (Exception e) {
            log.error("缓存读取异常", e);
            return null;
        }
    }

    public void cleanRecordCache(Long lessonId, Long id){
        // 删除redis缓存数据
        String key = StringUtils.format(RECORD_KEY_TEMPLATE,lessonId.toString());
        // 课表id为大key，小节id为小key
        redisTemplate.opsForHash().delete(key,id.toString());
    }

    @Data
    @NoArgsConstructor
    private static class RecordCacheData{
        private Long id;
        private Integer moment;
        private Boolean finished;

        public RecordCacheData(LearningRecord record) {
            this.id = record.getSectionId();
            this.moment = record.getMoment();
            this.finished = record.getFinished();
        }
    }
    @Data
    @NoArgsConstructor
    private static class RecordTaskData{
        private Long lessonId;
        private Long recordId;
        private Integer moment;

        public RecordTaskData(LearningRecord record) {
            this.lessonId = record.getLessonId();
            this.recordId = record.getSectionId();
            this.moment = record.getMoment();
        }
    }
}